﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.Xml.Serialization;
using Kinban.Contracts;

namespace Kinban.ViewModels
{
    public class TfsViewModel : INotifyPropertyChanged
    {
        //public IGetStoryUnderMouse GetStoryUnderMouse { get; set; }
        //private System.Threading.Timer underMouseTest;

        private System.Threading.Timer _refreshTimer;
        private Dispatcher _dispatcher;
        private List<Story> _stories;
        private Contracts.ITfsGateway _tfsGateway;

        public TfsViewModel(Contracts.ITfsGateway tfsGateway, IUserGateway userGateway)
        {
            _tfsGateway = tfsGateway;
            _stories = new List<Story>();
            //underMouseTest = new Timer(TestGetStoryUnderMouse, null, 5000, 5000);
            _dispatcher = Dispatcher.CurrentDispatcher;

            ProjectQueue = new KanbanQueue("Story Queue", new List<string> { "Development" });
            Development = new KanbanQueue("Development", new List<string> { "Story Queue", "Ready for test" });
            ReadyForTest = new KanbanQueue("Ready for test", new List<string> { "Development", "Test" });
            Testing = new KanbanQueue("Test", new List<string> { "Ready for test", "Done" });
            Done = new KanbanQueue("Done", new List<string> { "Test" });

            Users = new ObservableCollection<User>(userGateway.GetUsers());

            _refreshTimer = new Timer(LoadTfsData, "initial", TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(Properties.Settings.Default.TfsRefreshIntervalSeconds));
        }

        private void LoadTfsData(object state)
        {
            var projectNames = new List<string>(Properties.Settings.Default.TFSProjectNames.Cast<string>());
            var stories = _tfsGateway.GetStories(projectNames);

            _dispatcher.Invoke(new Action(() => { PopulateTfsViewModel(stories); }));
        }

        private void PopulateTfsViewModel(IEnumerable<Story> updatedStories)
        {
            // Unsubscribe all stories
            if (_stories != null)
            {
                _stories.Cast<INotifyPropertyChanged>().ToList().ForEach(s => s.PropertyChanged -= OnStoryChanged);
            }

            _stories.Clear();

            var stories = updatedStories.ToList();
            stories.ForEach(_stories.Add);

            Backlog = _stories.Count(w => w.State == "Backlog");
            Released = _stories.Count(w => w.State == "Released");

            ProjectQueue.SetStories(_stories.Where(s => s.State == "Story Queue"));
            Development.SetStories(_stories.Where(s => s.State == "Development"));
            ReadyForTest.SetStories(_stories.Where(s => s.State == "Ready for test"));
            Testing.SetStories(_stories.Where(s => s.State == "Test"));
            Done.SetStories(_stories.Where(s => s.State == "Done"));

            var validStates = new List<string> { "Backlog", "Released", "Story Queue", "Development", "Ready for test", "Test", "Done" };
            var invalidStateStories = _stories.Where(s => !validStates.Contains(s.State));
            invalidStateStories.ToList().ForEach(s =>
            {
                Debug.WriteLine("Story {0} has invalid state {1}.", s.Description, s.State);
            });

            // subscribe all stories for saving
            _stories.ForEach(s => s.PropertyChanged += OnStoryChanged);
        }

        private void OnStoryChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "State":
                case "AssignedTo":
                case "StartDate":
                case "EndDate":
                    SaveStory(sender as Story);
                    break;
                default:
                    break;
            }
        }

        private void SaveStory(Story story)
        {
            try
            {
                _tfsGateway.UpdateStory(story);
            }
            catch (Exception ex)
            {
                story.ErrorOccurred = true;
                story.ErrorMessage = ex.Message;

                _refreshTimer.Change(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(Properties.Settings.Default.TfsRefreshIntervalSeconds));
            }
        }

        //private void TestGetStoryUnderMouse(object state)
        //{
        //    if (GetStoryUnderMouse != null)
        //    {
        //        var story = GetStoryUnderMouse.GetStory();
        //        if (story != null)
        //        {
        //            Debug.WriteLine(story.Description);
        //        }
        //    }
        //}

        #region ProjectQueue (INotifyPropertyChanged Property)
        private KanbanQueue _projectQueue;

        public KanbanQueue ProjectQueue
        {
            get { return _projectQueue; }
            set
            {
                if (_projectQueue != value)
                {
                    _projectQueue = value;
                    RaisePropertyChanged("ProjectQueue");
                }
            }
        }
        #endregion

        #region Development (INotifyPropertyChanged Property)
        private KanbanQueue _development;

        public KanbanQueue Development
        {
            get { return _development; }
            set
            {
                if (_development != value)
                {
                    _development = value;
                    RaisePropertyChanged("Development");
                }
            }
        }
        #endregion

        #region ReadyForTest (INotifyPropertyChanged Property)
        private KanbanQueue _readyForTest;

        public KanbanQueue ReadyForTest
        {
            get { return _readyForTest; }
            set
            {
                if (_readyForTest != value)
                {
                    _readyForTest = value;
                    RaisePropertyChanged("ReadyForTest");
                }
            }
        }
        #endregion

        #region Testing (INotifyPropertyChanged Property)
        private KanbanQueue _testing;

        public KanbanQueue Testing
        {
            get { return _testing; }
            set
            {
                if (_testing != value)
                {
                    _testing = value;
                    RaisePropertyChanged("Testing");
                }
            }
        }
        #endregion

        #region Done (INotifyPropertyChanged Property)
        private KanbanQueue _done;
        public KanbanQueue Done
        {
            get { return _done; }
            set
            {
                if (_done != value)
                {
                    _done = value;
                    RaisePropertyChanged("Done");
                }
            }
        }
        #endregion

        #region People (INotifyPropertyChanged Property)
        private ObservableCollection<User> _users;
        public ObservableCollection<User> Users
        {
            get { return _users; }
            set
            {
                if (_users != value)
                {
                    _users = value;
                    RaisePropertyChanged("Users");
                }
            }
        }
        #endregion

        #region VideoImage (INotifyPropertyChanged Property)
        private BitmapSource _videoImage;

        public BitmapSource VideoImage
        {
            get { return _videoImage; }
            set
            {
                if (_videoImage != value)
                {
                    _videoImage = value;
                    RaisePropertyChanged("VideoImage");
                }
            }
        }
        #endregion

        #region DepthImage (INotifyPropertyChanged Property)
        private BitmapSource _depthImage;
        public BitmapSource DepthImage
        {
            get { return _depthImage; }
            set
            {
                if (_depthImage != value)
                {
                    _depthImage = value;
                    RaisePropertyChanged("DepthImage");
                }
            }
        }
        #endregion

        #region SelectedStory (INotifyPropertyChanged Property)
        private Story _selectedStory;
        public Story SelectedStory
        {
            get { return _selectedStory; }
            set
            {
                if (_selectedStory != value)
                {
                    _selectedStory = value;
                    RaisePropertyChanged("SelectedStory");
                }
            }
        }
        #endregion

        #region Backlog (INotifyPropertyChanged Property)
        private int _backlog;
        public int Backlog
        {
            get { return _backlog; }
            set
            {
                if (_backlog != value)
                {
                    _backlog = value;
                    RaisePropertyChanged("Backlog");
                }
            }
        }
        #endregion

        #region Released (INotifyPropertyChanged Property)
        private int _released;
        public int Released
        {
            get { return _released; }
            set
            {
                if (_released != value)
                {
                    _released = value;
                    RaisePropertyChanged("Released");
                }
            }
        }
        #endregion

        #region INotifyPropertyChanged values

        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

    }
}
